package com.piece.core.framework.support.convert;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.HashMap;
import java.util.Map;

/**
 * 数字转换器
 */
@Slf4j
public class NumberConvert {

    /**
     * 大写数字
     */
    private static final String[] NUMBER_CN = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};

    /**
     * 整数部分的单位
     */
    private static final String[] I_UNIT = {"元", "拾", "佰", "仟", "万", "拾", "佰", "仟", "亿", "拾", "佰", "仟", "万", "拾", "佰", "仟"};

    /**
     * 小数部分的单位
     */
    private static final String[] D_UNIT = {"角", "分", "厘"};

    /**
     * 大写数字字符
     */
    private static final Character[] NUMERIC_CN = {'一', '二', '三', '四', '五', '六', '七', '八', '九',
            '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖', '十', '百', '千', '拾', '佰', '仟', '万', '亿', '○', 'Ｏ', '零'};

    /**
     * 字符存储map
     */
    private static Map<Character, Integer> numeric = null;

    static {
        numeric = new HashMap<Character, Integer>(40, 0.85f);
        for (int j = 0; j < 9; j++)
            numeric.put(NUMERIC_CN[j], j + 1);
        for (int j = 9; j < 18; j++)
            numeric.put(NUMERIC_CN[j], j - 8);
        numeric.put('两', 2);
        numeric.put('十', 10);
        numeric.put('拾', 10);
        numeric.put('百', 100);
        numeric.put('佰', 100);
        numeric.put('千', 1000);
        numeric.put('仟', 1000);
        numeric.put('万', 10000);
        numeric.put('亿', 100000000);
    }

    /**
     * 数字金额转大写金额
     *
     * @param str 英文金额
     * @return 中文金额
     */
    public static String digitUppercase(String str) {
        if (StringUtils.isEmpty(str)) {
            return "";
        }
        // 去掉","
        str = str.replaceAll(",", "");
        // 整数部分数字
        String integerStr;
        // 小数部分数字
        String decimalStr;
        // 分离整数部分和小数部分
        if (str.indexOf(".") > 0) {
            integerStr = str.substring(0, str.indexOf("."));
            decimalStr = str.substring(str.indexOf(".") + 1);
        } else if (str.indexOf(".") == 0) {
            integerStr = "";
            decimalStr = str.substring(1);
        } else {
            integerStr = str;
            decimalStr = "";
        }
        if (!integerStr.equals("")) {
            // 去掉开头的0
            integerStr = Long.toString(Long.parseLong(integerStr));
            if (integerStr.equals("0")) {
                integerStr = "";
            }
        }
        // 超出处理能力，直接返回
        if (integerStr.length() > I_UNIT.length) {
            log.error("金额转换超出处理范围:{}", str);
            return str;
        }
        // 整数部分数字
        int[] integers = numberToArray(integerStr);
        // 小数部分数字
        int[] decimals = numberToArray(decimalStr);
        return getUpperCaseInteger(integers) + getUpperCaseDecimal(decimals);
    }

    /**
     * 数字转换为数组，从高位至低位
     */
    private static int[] numberToArray(String number) {
        int[] array = new int[number.length()];
        for (int i = 0; i < number.length(); i++) {
            array[i] = Integer.parseInt(number.substring(i, i + 1));
        }
        return array;
    }

    /**
     * 得到中文金额的整数部分
     */
    private static String getUpperCaseInteger(int[] integers) {
        StringBuffer chineseInteger = new StringBuffer();
        int length = integers.length;
        for (int i = 0; i < length; i++) {
            // 0出现在关键位置：1234(万)5678(亿)9010(万)3456(元) 106000
            // 特殊情况：10(拾元、壹拾元、壹拾万元、拾万元)
            String key = "";
            if (integers[i] == 0) {
                if ((length - i) == 13)// 万(亿)(必填)
                    key = I_UNIT[4];
                else if ((length - i) == 9)// 亿(必填)
                    key = I_UNIT[8];
                else if ((length - i) == 5)// 万(必填)
                    key = I_UNIT[12];
                else if ((length - i) == 1)// 元(必填)
                    key = I_UNIT[0];
                // 0遇非0时补零，不包含最后一位
                if ((length - i) > 1 && integers[i + 1] != 0 && key == "")
                    key += NUMBER_CN[0];
            }
            chineseInteger.append(integers[i] == 0 ? key
                    : (NUMBER_CN[integers[i]] + I_UNIT[length - i - 1]));
        }
        return chineseInteger.toString();
    }

    /**
     * 得到中文金额的小数部分
     */
    private static String getUpperCaseDecimal(int[] decimals) {
        StringBuffer chineseDecimal = new StringBuffer();
        for (int i = 0; i < decimals.length; i++) {
            // 舍去3位小数之后的
            if (i == 3)
                break;
            chineseDecimal.append(decimals[i] == 0 ? ""
                    : (NUMBER_CN[decimals[i]] + D_UNIT[i]));
        }
        return chineseDecimal.toString();
    }

    /**
     * 中文数字转阿拉伯数字
     */
    public static int cnNumericToArabic(String cnn) {
        cnn = cnn.trim();
        if (cnn.length() == 1)
            return isCNNumeric(cnn.charAt(0));

        cnn = cnn.replace('佰', '百').replace('仟', '千').replace('拾', '十').replace('零', ' ');

        int yi = -1, wan = -1, qian = -1, bai = -1, shi = -1;
        int val = 0;
        yi = cnn.lastIndexOf('亿');
        if (yi > -1) {
            val += cnNumericToArabic(cnn.substring(0, yi)) * 100000000;
            if (yi < cnn.length() - 1)
                cnn = cnn.substring(yi + 1);
            else
                cnn = "";

            if (cnn.length() == 1) {
                int arbic = isCNNumeric(cnn.charAt(0));
                if (arbic <= 10)
                    val += arbic * 10000000;
                cnn = "";
            }
        }

        wan = cnn.lastIndexOf('万');
        if (wan > -1) {
            val += cnNumericToArabic(cnn.substring(0, wan)) * 10000;
            if (wan < cnn.length() - 1)
                cnn = cnn.substring(wan + 1);
            else
                cnn = "";
            if (cnn.length() == 1) {
                int arbic = isCNNumeric(cnn.charAt(0));
                if (arbic <= 10)
                    val += arbic * 1000;
                cnn = "";
            }
        }

        qian = cnn.lastIndexOf('千');
        if (qian > -1) {
            val += cnNumericToArabic(cnn.substring(0, qian)) * 1000;
            if (qian < cnn.length() - 1)
                cnn = cnn.substring(qian + 1);
            else
                cnn = "";
            if (cnn.length() == 1) {
                int arbic = isCNNumeric(cnn.charAt(0));
                if (arbic <= 10)
                    val += arbic * 100;
                cnn = "";
            }
        }

        bai = cnn.lastIndexOf('百');
        if (bai > -1) {
            val += cnNumericToArabic(cnn.substring(0, bai)) * 100;
            if (bai < cnn.length() - 1)
                cnn = cnn.substring(bai + 1);
            else
                cnn = "";
            if (cnn.length() == 1) {
                int arbic = isCNNumeric(cnn.charAt(0));
                if (arbic <= 10)
                    val += arbic * 10;
                cnn = "";
            }
        }

        shi = cnn.lastIndexOf('十');
        if (shi > -1) {
            if (shi == 0)
                val += 1 * 10;
            else
                val += cnNumericToArabic(cnn.substring(0, shi)) * 10;
            if (shi < cnn.length() - 1)
                cnn = cnn.substring(shi + 1);
            else
                cnn = "";
        }

        cnn = cnn.trim();
        for (int j = 0; j < cnn.length(); j++)
            val += isCNNumeric(cnn.charAt(j)) * Math.pow(10, cnn.length() - j - 1);

        return val;
    }

    /**
     * 中文单位转数字
     */
    private static int isCNNumeric(char c) {
        Integer i = numeric.get(c);
        if (null == i)
            return -1;
        return i.intValue();
    }
}
